K-Means en R ------------ **Importar datos:** .. code:: r datos <- read.csv("EAM_2019-v2.csv", sep = ";", dec = ",", header = T) print(head(datos)) .. parsed-literal:: ï..gasto_personal inversion_AF ventas 1 32334949 92544622 321070109 2 5669798 69317638 86597330 3 11081213 50853587 26727389 4 47892609 42426113 388005721 5 56410101 35164028 390070138 6 20536798 27028346 490639882 .. code:: r dim(datos) .. raw:: html
  1. 216
  2. 3
.. code:: r str(datos) .. parsed-literal:: 'data.frame': 216 obs. of 3 variables: $ ï..gasto_personal: int 32334949 5669798 11081213 47892609 56410101 20536798 14001910 38533922 21397321 3478034 ... $ inversion_AF : int 92544622 69317638 50853587 42426113 35164028 27028346 25150313 23019658 22007282 21924323 ... $ ventas : int 321070109 86597330 26727389 388005721 390070138 490639882 379365700 488079500 233432780 9932602 ... .. code:: r colnames(datos) <- c("Gasto_personal", "Inversión_AF", "Ventas") Creamos una variable para almacenar solo las variables que queremos analizar. .. code:: r df <- datos[, c("Gasto_personal", "Ventas")] **Dispersión de los datos:** .. code:: r library(ggplot2) .. code:: r ggplot(data = df)+ geom_point(aes(x = Gasto_personal, y = Ventas)) .. image:: output_10_0.png :width: 420px :height: 420px Escalamiento de variables: ~~~~~~~~~~~~~~~~~~~~~~~~~~ Para Normalizar usaremos la función ``scale()``. .. math:: Normalización = X_{norm} = \frac{x_i-\overline{x}}{\sigma_x} .. code:: r df_scaled <- scale(df) df_scaled <- data.frame(df_scaled) # Data Frame para ggplot2 print(head(df_scaled)) .. parsed-literal:: Gasto_personal Ventas 1 1.52915807 1.9822451 2 -0.47700945 -0.1241207 3 -0.06987862 -0.6619571 4 2.69964731 2.5835553 5 3.34046558 2.6021008 6 0.64151759 3.5055604 **Dispersión de los datos escalados:** .. code:: r ggplot(data = df_scaled)+ geom_point(aes(x = Gasto_personal, y = Ventas)) .. image:: output_15_0.png :width: 420px :height: 420px **Distancia Euclideana:** .. math:: D_1(x_i, x_j) =\sqrt{\sum_{k=1}^p{(x_{ix}-x_{jx})^2}} Con la función ``dist()`` podemos calcular diferentes distancias con el argumento ``method =``: ``"euclidean"``, ``"manhattan"``, ``"minkowski"``, entre otros. Cuando se usa la distancia ``"minkowski"`` se debe agregar el argumento ``p =``. .. code:: r dist_eucl <- dist(df_scaled, method = "euclidean") **Matriz de distancias:** De forma matricial se muestran las distancias entre todas las observaciones. La diagonal es cero porque es la distancia entre cada observación con ella misma. Por ejemplo: la distancia Euclidiana entre la observación uno y dos es 2,9. Resta al cuadrado de la fila 1 con la fila 2 y el resultado se saca raíz cuadrada así: .. code:: r print(sqrt((df_scaled[1,1]-df_scaled[2,1])^2+(df_scaled[1,2]-df_scaled[2,2])^2)) .. parsed-literal:: [1] 2.908863 Se sacará la matriz para las distancias entre las primeras 10 observaciones. .. code:: r print(round(as.matrix(dist_eucl)[1:10, 1:10], 1)) .. parsed-literal:: 1 2 3 4 5 6 7 8 9 10 1 0.0 2.9 3.1 1.3 1.9 1.8 1.5 1.6 1.1 3.5 2 2.9 0.0 0.7 4.2 4.7 3.8 2.7 4.4 1.8 0.7 3 3.1 0.7 0.0 4.3 4.7 4.2 3.2 4.6 2.0 0.6 4 1.3 4.2 4.3 0.0 0.6 2.3 2.6 1.1 2.4 4.8 5 1.9 4.7 4.7 0.6 0.0 2.8 3.2 1.6 3.0 5.2 6 1.8 3.8 4.2 2.3 2.8 0.0 1.1 1.4 2.3 4.5 7 1.5 2.7 3.2 2.6 3.2 1.1 0.0 2.1 1.4 3.4 8 1.6 4.4 4.6 1.1 1.6 1.4 2.1 0.0 2.6 5.0 9 1.1 1.8 2.0 2.4 3.0 2.3 1.4 2.6 0.0 2.4 10 3.5 0.7 0.6 4.8 5.2 4.5 3.4 5.0 2.4 0.0 K-Means: ~~~~~~~~ La función más usada es ``kmeans()`` de la librería ``stats``. Instalar el siguiente paquete: ``install.packages("stats")`` **sintaxis:** ``kmeans(x, centers, iter.max = 10, nstart = 1)`` ``x``: Data Frame con los datos, agregaremos las distancias calculadas con ``dist()``. ``centers``: son los :math:`k` clusters iniciales. ``iter.max``: número máximo de iteraciones. Por defecto es 10. ``nstart``: número de particiones iniciales aleatorias cuando ``centers`` es un número. Probar con ``nstart > 1`` .. code:: r set.seed(1) # valor semilla para obtener siempre los mismos resultados. .. code:: r names(kmeans(dist_eucl, 10)) .. raw:: html
  1. 'cluster'
  2. 'centers'
  3. 'totss'
  4. 'withinss'
  5. 'tot.withinss'
  6. 'betweenss'
  7. 'size'
  8. 'iter'
  9. 'ifault'
``cluster``: un vector de enteros (desde 1:k) que indica el cluster al que se asigna cada punto. ``centers``: una matriz con los centroides. ``withinss``: vector con los WCSS de cada cluster. El resultado es después de definir la cantidad de clusters. ``size``: cantidad de puntos en cada cluster. Número óptimo de clusters: ~~~~~~~~~~~~~~~~~~~~~~~~~~ **Método del codo:** Se calculará el valor de WCSS aplicando K-Means aumentando la cantidad de centroides. .. code:: r wcss = vector() for (i in 1:10){ wcss[i] <- sum(kmeans(df_scaled, i)$withinss) } ggplot()+geom_line(aes(x = c(1:10), y = wcss), size = 1)+ geom_vline(xintercept = 6, color = "darkred")+ labs(title = "Método del codo", x = "k clusters", y = "WCSS")+ theme_light() .. image:: output_34_0.png :width: 420px :height: 420px Este método también lo podemos hacer con la función ``fviz_nbclust()`` del paquete ``factoextra``. ``install.packages("factoextra")`` .. code:: r library(factoextra) .. parsed-literal:: Warning message: "package 'factoextra' was built under R version 4.1.3" Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa .. code:: r fviz_nbclust(df_scaled, kmeans, method = "wss") + geom_vline(xintercept = 6, linetype = 2)+ labs(subtitle = "Método del codo") .. image:: output_37_0.png :width: 420px :height: 420px Método de la silueta: ~~~~~~~~~~~~~~~~~~~~~ Este método también lo hacemos con la función ``fviz_nbclust()`` .. code:: r fviz_nbclust(df_scaled, kmeans, method = "silhouette")+ labs(subtitle = "Método de la silueta") .. image:: output_40_0.png :width: 420px :height: 420px Método del gap estadístico: ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code:: r fviz_nbclust(df_scaled, kmeans, method = "gap_stat")+ labs(subtitle = "Gap statistic method") .. image:: output_42_0.png :width: 420px :height: 420px Aplicación del K-Means con k óptimo: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :math:`k = 3`: Recomiendo llamar el modelo de cualquier forma diferente a ``kmeans`` por este nombre se utiliza para algunas librerías como función y no como una variable; por ejemplo, guardemos el resultado con el nombre de ``k_means``. .. code:: r k_means <- kmeans(dist_eucl, 3, iter.max = 300, nstart = 10) **Cantidad de observaciones por cada cluster:** ¿Cómo cambia este resultado para 3 clusters? .. code:: r print(k_means$size) .. parsed-literal:: [1] 15 46 155 Para visualizar los clusters en los datos originales usaremos la función ``clusplot()`` del paquete ``cluster``. Instalar el paquete: ``install.packages("cluster")`` .. code:: r library(cluster) .. parsed-literal:: Warning message: "package 'cluster' was built under R version 4.1.3" .. code:: r clusplot(df, k_means$cluster, # el cluster que se le asigna a cada punto. lines = 0, # para eliminar líneas en el gráfico. labels = 4, # 4 para que ponga una etiqueta al número del cluster. color = TRUE, # diferente colo para cada sector. plotchar = FALSE, # con FALSE se quitan los símbolos diferentes para cada cluster. span = TRUE, # TRUE para que represente el cluster con una elipse no como círculo. main = "Clustering de empresas", xlab = "Activos Totales", ylab = "Ingresos Operacionales" ) .. image:: output_51_0.png :width: 420px :height: 420px Otra forma de visualizar los cluster con ``fviz_cluster()`` .. code:: r fviz_cluster(k_means, data = df, stand = FALSE, # FALSE para que no estandarice los datos, ya se había hecho esto. show.clust.cent = TRUE, # TRUE para que muestre los centroides. ellipse = TRUE, # Puede ser FALSE o TRUE ggtheme = theme_minimal()) .. image:: output_53_0.png :width: 420px :height: 420px Es posible calcular la media de cada variable por cluster utilizando los datos originales: .. code:: r print(aggregate(df, by = list(cluster = k_means$cluster), mean)) .. parsed-literal:: cluster Gasto_personal Ventas 1 1 46055433 390956062 2 2 19831448 197627597 3 3 6394092 43446519 :math:`k = 6`: .. code:: r k_means <- kmeans(dist_eucl, 6, iter.max = 300, nstart = 10) print(k_means$size) .. parsed-literal:: [1] 2 115 37 12 20 30 .. code:: r fviz_cluster(k_means, data = df, stand = FALSE, # FALSE para que no estandarice los datos, ya se había hecho esto. show.clust.cent = TRUE, # TRUE para que muestre los centroides. ellipse = TRUE, # Puede ser FALSE o TRUE ggtheme = theme_minimal()) .. image:: output_58_0.png :width: 420px :height: 420px **Realizar el K-Means con distancias Manhattan y Minkowski con p igual 0.1, 0.5, 3 y 4.** **Realizar lo anterior, pero sin estandarizar las variables** **¿Para este caso en específico será necesario la estandarización de variables?** **Realizar el K-Means con las siguientes variables: Inversión en AF y Ventas**